home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / tests / fstrash / fstrash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-10  |  48.7 KB  |  1,630 lines

  1. /* 
  2.  * fstrash.c --
  3.  *
  4.  *    Format a domain to be a filesystem with lots of errors. This program 
  5.  *    is intended to be a test for fscheck. Refer to fstrash.man for details
  6.  *    on the filesystem created and the actions fscheck should take to 
  7.  *    correct it.
  8.  *    Warning - the trashed filesystem has been constructed by hand, and as
  9.  *    a result this code is very sensitive to changes. If you want to add a
  10.  *    new file you must do the following things:
  11.  *     - find an available file descriptor (see man page)
  12.  *     - find available data blocks (see man page)
  13.  *     - create a routine to fill in the descriptor (SetFooFD)
  14.  *     - add a call to this routine in WriteFileDesc
  15.  *     - mark the fd as in use in MakeFileDescBitmap
  16.  *     - mark the data blocks as in use in WriteBitmap
  17.  *     - add the file as an entry in a directory (WriteRootDirectory)
  18.  *     - if the new file is a directory create a new routine to fill in
  19.  *        the directory (WriteFoo) and add a call to this routine in
  20.  *        MakeFilesystem
  21.  *    Since you are creating a trashed file system you may want to skip some
  22.  *    of the above steps. Just make sure that you don't do something 
  23.  *    unexpected by using blocks that are already in use, forgetting to
  24.  *    add the file to a directory, etc. 
  25.  *
  26.  * Copyright 1989 Regents of the University of California
  27.  * Permission to use, copy, modify, and distribute this
  28.  * software and its documentation for any purpose and without
  29.  * fee is hereby granted, provided that the above copyright
  30.  * notice appear in all copies.  The University of California
  31.  * makes no representations about the suitability of this
  32.  * software for any purpose.  It is provided "as is" without
  33.  * express or implied warranty.
  34.  */
  35.  
  36. #ifndef lint
  37. static char rcsid[] = "$Header: /sprite/src/tests/fstrash/RCS/fstrash.c,v 1.4 89/06/19 14:19:31 jhh Exp $ SPRITE (Berkeley)";
  38. #endif not lint
  39.  
  40. #include "sprite.h"
  41. #include "option.h"
  42. #include "disk.h"
  43. #include <stdio.h>
  44. #include <sys/file.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47.  
  48. /*
  49.  * Constants settable via the command line.
  50.  */
  51. int kbytesToFileDesc = 4;    /* The ratio of kbytes to
  52.                  * the number of file descriptors */
  53. Boolean printOnly = TRUE;    /* Stop after computing the domain header
  54.                  * and just print it out. No disk writes */
  55. Boolean copySuperBlock = FALSE;    /* Copy the super block from the first
  56.                  * disk partition to the one being formatted */
  57. Boolean makeFile = TRUE;    /* Make a file in the root directory,
  58.                  * this is used when testing the filesystem */
  59. Boolean overlapBlocks = FALSE;    /* Allow filesystem blocks to overlap track
  60.                  * boundaries.  Some disk systems can't deal. */
  61. Boolean rootFree = FALSE;    /* Mark the root as free */
  62. Boolean rootFile = FALSE;    /* Make the root a file */
  63. Boolean noRoot = FALSE;        /* Zero out the root fd and block 0 */
  64. Boolean scsiDisk = TRUE;    /* If TRUE then simpler geometry is computed
  65.                  * that knows that SCSI controllers don't
  66.                  * think in terms of cylinders, heads, and
  67.                  * sectors.  Instead, they think in terms of
  68.                  * logical sector numbers, so we punt on finding
  69.                  * rotationally optimal block positions. */
  70. /*
  71.  * The following are used to go from a command line like
  72.  * makeFilesystem -D rsd0 -P b
  73.  * to /dev/rsd0a     - for the partition that has the disk label
  74.  * and to /dev/rsd0b    - for the partition to format.
  75.  */
  76. char *deviceName;        /* Set to "rsd0" or "rxy1", etc. */
  77. char *partName;            /* Set to "a", "b", "c" ... "g" */
  78. char defaultFirstPartName[] = "a";
  79. char *firstPartName = defaultFirstPartName;
  80. char defaultDevDirectory[] = "/dev/";
  81. char *devDirectory = defaultDevDirectory;
  82.  
  83. Option optionArray[] = {
  84.     {OPT_STRING, "dev", (Address)&deviceName,
  85.     "Required: Name of device, eg \"rsd0\" or \"rxy1\""},
  86.     {OPT_STRING, "part", (Address)&partName,
  87.     "Required: Partition ID: (a, b, c, d, e, f, g)"},
  88.     {OPT_TRUE, "overlap", (Address)&overlapBlocks,
  89.     "Overlap filesystem blocks across track boundaries (FALSE)"},
  90.     {OPT_TRUE, "copySuper", (Address)©SuperBlock,
  91.     "Copy the super block to the partition (FALSE)"},
  92.     {OPT_INT, "ratio", (Address)&kbytesToFileDesc,
  93.     "Ratio of Kbytes to file descriptors (4)"},
  94.     {OPT_TRUE, "test", (Address)&printOnly,
  95.     "Print results, don't write disk (TRUE)"},
  96.     {OPT_FALSE, "write", (Address)&printOnly,
  97.     "Write the disk (FALSE)"},
  98.     {OPT_STRING, "dir", (Address)&devDirectory,
  99.     "Name of device directory (\"/dev/\")"},
  100.     {OPT_STRING, "initialPart", (Address)&firstPartName,
  101.     "Name of initial partition (\"a\")"},
  102.     {OPT_TRUE, "freeRoot", (Address)&rootFree,
  103.     "Mark root fd as being free. (FALSE)"},
  104.     {OPT_TRUE, "fileRoot", (Address)&rootFile,
  105.     "Mark root fd as being a file. (FALSE)"},
  106.     {OPT_TRUE, "noRoot", (Address)&noRoot,
  107.     "Zero out root fd and block 0 (FALSE)"},
  108.     {OPT_FALSE, "noscsi", (Address)&scsiDisk,
  109.     "Compute geometry for non-SCSI disk (FALSE)"},
  110.  
  111. };
  112. int numOptions = sizeof(optionArray) / sizeof(Option);
  113.  
  114. /*
  115.  * Forward Declarations.
  116.  */
  117. void SetSummaryInfo();
  118. void SetDomainHeader();
  119. void SetDiskGeometry();
  120. void SetSCSIDiskGeometry();
  121. void SetDomainParts();
  122. void SetRootFileDescriptor();
  123. void SetBadBlockFileDescriptor();
  124. void SetLostFoundFileDescriptor();
  125. void SetEmptyFileDescriptor();
  126. void SetTooBigFD();
  127. void SetTooSmallFD();
  128. void SetHoleFileFD();
  129. void SetHoleDirFD();
  130. void SetBadEntryFileFD();
  131. void SetFragFileFD();
  132. void SetCopyFragFileFD();
  133. void SetCopyBlockFileFD();
  134. void SetCopyIndBlockFileFD();
  135. void SetCopyBogusIndBlockFileFD();
  136. void SetDirFD();
  137. ReturnStatus WriteFileDesc();
  138. ReturnStatus WriteFileDescBitmap();
  139. ReturnStatus WriteBitmap();
  140. char *MakeFileDescBitmap();
  141.  
  142. #define Max(a,b) ((a) > (b)) ? (a) : (b)
  143.  
  144.  
  145. /*
  146.  *----------------------------------------------------------------------
  147.  *
  148.  * main --
  149.  *
  150.  *    Create the required file names from the command line
  151.  *    arguments.  Then open the first partition on the disk
  152.  *    because it contains the disk label, and open the partition
  153.  *    that is to be formatted.
  154.  *
  155.  * Results:
  156.  *    None.
  157.  *
  158.  * Side effects:
  159.  *    Calls MakeFilesystem
  160.  *
  161.  *----------------------------------------------------------------------
  162.  */
  163. main(argc, argv)
  164.     int argc;
  165.     char *argv[];
  166. {
  167.     ReturnStatus status;    /* status of system calls */
  168.     int firstPartFID;        /* File ID for first parition on the disk */
  169.     int partFID;        /* File ID for partiton to format */
  170.     char firstPartitionName[64];
  171.     char partitionName[64];
  172.     int partition;        /* Index of partition derived from the
  173.                  * partition name */
  174.     int spriteID;        /* Host ID of the machine with the disks */
  175.     Fs_Attributes attrs;
  176.     char     answer[100];
  177.  
  178.     (void)Opt_Parse(argc, argv,optionArray, numOptions, 0);
  179.  
  180.     status = SUCCESS;
  181.     if (deviceName == (char *)0) {
  182.     fprintf(stderr,"Specify device name with -dev option\n");
  183.     status = FAILURE;
  184.     }
  185.     if (partName == (char *)0) {
  186.     fprintf(stderr,"Specify partition with -part option\n");
  187.     status = FAILURE;
  188.     }
  189.     if (status != SUCCESS) {
  190.     exit(status);
  191.     }
  192.     if (!printOnly) {
  193.     printf("The \"-write\" option will cause fstrash to overwrite the current filesystem.\nDo you really want to do this?[y/n] ");
  194.     if (scanf("%10s",answer) != 1) {
  195.         exit(SUCCESS);
  196.     }
  197.     if ((*answer != 'y') && (*answer != 'Y')) {
  198.         exit(SUCCESS);
  199.     }
  200.     }
  201.  
  202.  
  203.     /*
  204.      * Gen up the name of the first partition on the disk,
  205.      * and the name of the parition that needs to be formatted.
  206.      */
  207.     (void) strcpy(firstPartitionName, devDirectory);    /* eg. /dev/ */
  208.     (void) strcpy(partitionName, devDirectory);
  209.     (void) strcat(firstPartitionName, deviceName);    /* eg. /dev/rxy0 */
  210.     (void) strcat(partitionName, deviceName);
  211.     (void) strcat(firstPartitionName, firstPartName);    /* eg. /dev/rxy0a */
  212.     (void) strcat(partitionName, partName);        /* eg. /dev/rxy0b */
  213.  
  214.  
  215.     firstPartFID = open(firstPartitionName, O_RDONLY);
  216.     if (firstPartFID < 0 ) {
  217.     perror("Can't open first partition");
  218.     exit(FAILURE);
  219.     }
  220.     partFID = open(partitionName, O_RDWR);
  221.     if (partFID < 0) {
  222.     perror("Can't open partition to format");
  223.     exit(FAILURE);
  224.     }
  225.  
  226.     partition = partName[0] - 'a';
  227.     if (partition < 0 || partition > 7) {
  228.     fprintf(stderr,
  229.            "Can't determine partition index from the partition name\n");
  230.     exit(FAILURE);
  231.     }
  232.  
  233.     /*
  234.      * Determine where the disk is located so we can set the
  235.      * spriteID in the header correctly.
  236.      */
  237.     Fs_GetAttributesID(firstPartFID, &attrs);
  238.     if (attrs.devServerID == FS_LOCALHOST_ID) {
  239.     Sys_GetMachineInfo(NULL, NULL, &spriteID);
  240.     printf("Making filesystem for local host, ID = 0x%x\n", spriteID);
  241.     } else {
  242.     spriteID = attrs.devServerID;
  243.     printf("Making filesystem for remote host 0x%x\n", spriteID);
  244.     }
  245.     printf("MakeFilesystem based on 4K filesystem blocks\n");
  246.     status = MakeFilesystem(firstPartFID, partFID, partition, spriteID);
  247.  
  248.     fflush(stderr);
  249.     fflush(stdout);
  250.     (void)close(firstPartFID);
  251.     (void)close(partFID);
  252.     exit(status);
  253. }
  254.  
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * MakeFilesystem --
  259.  *
  260.  *    Format a disk partition, or domain.
  261.  *
  262.  * Results:
  263.  *    An error code.
  264.  *
  265.  * Side effects:
  266.  *    Write all over the disk partition.
  267.  *
  268.  *----------------------------------------------------------------------
  269.  */
  270. ReturnStatus
  271. MakeFilesystem(firstPartFID, partFID, partition, spriteID)
  272.     int firstPartFID;    /* Handle on the first partition of the disk */
  273.     int partFID;    /* Handle on the partition of the disk to format */
  274.     int partition;    /* Index of parition that is to be formatted */
  275.     int spriteID;    /* Host ID of the machine with the disks, this
  276.              * gets written on the disk and used at boot time */
  277. {
  278.     ReturnStatus status;
  279.     Disk_Label *labelPtr;
  280.     Fsdm_DomainHeader *headerPtr;
  281.     Fsdm_SummaryInfo *summaryPtr;
  282.  
  283.     /*
  284.      * Read the copy of the super block at the beginning of the partition
  285.      * to find out basic disk geometry and where to write the domain header.
  286.      */
  287.     labelPtr = Disk_ReadLabel(firstPartFID);
  288.     if (labelPtr == (Disk_Label *)0) {
  289.     fprintf(stderr,"MakeFilesystem: Unable to read disk label.\n");
  290.     return(FAILURE);
  291.     }
  292.  
  293.     headerPtr = (Fsdm_DomainHeader *)
  294.     malloc((unsigned) labelPtr->numDomainSectors * DEV_BYTES_PER_SECTOR);
  295.     SetDomainHeader(labelPtr, headerPtr, spriteID, partition);
  296.     Disk_PrintDomainHeader(headerPtr);
  297.  
  298.     if (!printOnly) {
  299.     if (copySuperBlock && partition != 0) {
  300.         status = CopySuperBlock(firstPartFID, partFID);
  301.         if (status != SUCCESS) {
  302.         perror("CopySuperBlock failed"); 
  303.         return(status);
  304.         }
  305.     }
  306.     status = Disk_SectorWrite(partFID, labelPtr->domainSector,
  307.                 labelPtr->numDomainSectors, (Address)headerPtr);
  308.     if (status != SUCCESS) {
  309.         perror("DomainHeader write failed");
  310.         return(status);
  311.     }
  312.     }
  313.     summaryPtr = (Fsdm_SummaryInfo *) malloc(DEV_BYTES_PER_SECTOR);
  314.     SetSummaryInfo(labelPtr, headerPtr, summaryPtr);
  315.     Disk_PrintSummaryInfo(summaryPtr);
  316.     if (!printOnly) {
  317.     status = Disk_SectorWrite(partFID, labelPtr->summarySector, 1,
  318.                 (Address)summaryPtr);
  319.     if (status != SUCCESS) {
  320.         perror("Summary sector  write failed");
  321.         return(status);
  322.     }
  323.     }
  324.  
  325.     status = WriteFileDesc(headerPtr, partFID);
  326.     if (status != SUCCESS) {
  327.     perror("WriteFileDesc failed");
  328.     return(status);
  329.     }
  330.     status = WriteBitmap(headerPtr, partFID);
  331.     if (status != SUCCESS) {
  332.     perror("WriteBitmap failed");
  333.     return(status);
  334.     }
  335.     status = WriteRootDirectory(headerPtr, partFID);
  336.     if (status != SUCCESS) {
  337.     perror("WriteRootDirectory failed");
  338.     return(status);
  339.     }
  340.     status = WriteLostFoundDirectory(headerPtr, partFID);
  341.     if (status != SUCCESS) {
  342.     perror("WriteLostFoundDirectory failed");
  343.     return(status);
  344.     }
  345.     status = WriteEmptyDirectory(headerPtr, partFID, 17, 16, 64);
  346.     if (status != SUCCESS) {
  347.     perror("WriteEmptyDirectory failed");
  348.     return(status);
  349.     }
  350.     status = WriteEmptyDirectory(headerPtr, partFID, 9, 2, 32);
  351.     if (status != SUCCESS) {
  352.     perror("WriteEmptyDirectory failed");
  353.     return(status);
  354.     }
  355.     status = WriteBadDotDotDirectory(headerPtr, partFID, 21, 2, 76);
  356.     if (status != SUCCESS) {
  357.     perror("WriteEmptyDirectory failed");
  358.     return(status);
  359.     }
  360.     return(SUCCESS);
  361. }
  362.  
  363. /*
  364.  *----------------------------------------------------------------------
  365.  *
  366.  * CopySuperBlock --
  367.  *
  368.  *    Copy the super block from the first sector of the disk to
  369.  *    the first sector of the partition being formatted.
  370.  *
  371.  * Results:
  372.  *    A return code from the I/O.
  373.  *
  374.  * Side effects:
  375.  *    Writes on the zero'th sector of the partition.
  376.  *
  377.  *----------------------------------------------------------------------
  378.  */
  379. ReturnStatus
  380. CopySuperBlock(firstPartFID, partFID)
  381.     int firstPartFID;
  382.     int partFID;
  383. {
  384.     ReturnStatus status;
  385.     char *block;
  386.  
  387.     block = (char *)malloc(DEV_BYTES_PER_SECTOR);
  388.  
  389.     status = Disk_SectorRead(firstPartFID, 0, 1, block);
  390.     if (status != SUCCESS) {
  391.     return(status);
  392.     }
  393.     status = Disk_SectorWrite(partFID, 0, 1, block);
  394.     return(status);
  395. }
  396.  
  397. /*
  398.  *----------------------------------------------------------------------
  399.  *
  400.  * SetDomainHeader --
  401.  *
  402.  *    Compute the domain header based on the partition size and
  403.  *    other basic disk parameters.
  404.  *
  405.  * Results:
  406.  *    A return code.
  407.  *
  408.  * Side effects:
  409.  *    Fill in the domain header.
  410.  *
  411.  *----------------------------------------------------------------------
  412.  */
  413. void
  414. SetDomainHeader(labelPtr, headerPtr, spriteID, partition)
  415.     Disk_Label *labelPtr;    /* Information from the super block */
  416.     Fsdm_DomainHeader *headerPtr;    /* Reference to domain header to fill in */
  417.     int spriteID;        /* Host ID of machine with the disks */
  418.     int partition;        /* Index of partition to format */
  419. {
  420.     Fsdm_Geometry *geoPtr;/* The layout information for the disk */
  421.  
  422.     headerPtr->magic = FSDM_DOMAIN_MAGIC;
  423.     headerPtr->firstCylinder = labelPtr->partitions[partition].firstCylinder;
  424.     headerPtr->numCylinders = labelPtr->partitions[partition].numCylinders;
  425.     /*
  426.      * The device.serverID from the disk is used during boot to discover
  427.      * the host"s spriteID if reverse arp couldn't find a host ID.  The
  428.      * unit number of disk indicates what partition of the disk this
  429.      * domain header applies to.  For example, both the "a" and "c" partitions
  430.      * typically start at sector zero, but only one is valid.  During boot
  431.      * time the unit number is used to decide which partition should be
  432.      * attached.
  433.      */
  434.     headerPtr->device.serverID = spriteID;
  435.     headerPtr->device.type = -1;
  436.     headerPtr->device.unit = partition;
  437.     headerPtr->device.data = (ClientData)-1;
  438.  
  439.     geoPtr = &headerPtr->geometry;
  440.     if (scsiDisk) {
  441.     SetSCSIDiskGeometry(labelPtr, geoPtr);
  442.     } else {
  443.     SetDiskGeometry(labelPtr, geoPtr);
  444.     }
  445.     SetDomainParts(labelPtr, partition, headerPtr);
  446. }
  447.  
  448. /*
  449.  *----------------------------------------------------------------------
  450.  *
  451.  * SetSCSIDiskGeometry --
  452.  *
  453.  *    This computes the rotational set arrangment depending on the
  454.  *    disk geometry.  No fancy block skewing is done.  The cylinders
  455.  *    are divided into rotational sets that minimize the amount of
  456.  *    wasted space.
  457.  *
  458.  * Results:
  459.  *    None.
  460.  *
  461.  * Side effects:
  462.  *    Fill in the geometry struct.
  463.  *
  464.  *----------------------------------------------------------------------
  465.  */
  466. void
  467. SetSCSIDiskGeometry(labelPtr, geoPtr)
  468.     Disk_Label        *labelPtr;    /* The disk label. */
  469.     Fsdm_Geometry     *geoPtr;    /* Fancy geometry information */
  470. {
  471.     int index;        /* Array index */
  472.     int blocksPerCyl;        /* The number of blocks in a cylinder */
  473.  
  474.     geoPtr->numHeads = labelPtr->numHeads;
  475.     geoPtr->sectorsPerTrack = labelPtr->numSectors;
  476.  
  477.     blocksPerCyl = geoPtr->sectorsPerTrack * geoPtr->numHeads /
  478.         DISK_SECTORS_PER_BLOCK;
  479.  
  480.     printf("Disk has %d tracks/cyl, %d sectors/track\n",
  481.         geoPtr->numHeads, geoPtr->sectorsPerTrack);
  482.     printf("%d 4K Blocks fit on a cylinder with %d 512 byte sectors wasted\n",
  483.         blocksPerCyl, geoPtr->sectorsPerTrack * geoPtr->numHeads - 
  484.         blocksPerCyl * DISK_SECTORS_PER_BLOCK);
  485.     geoPtr->rotSetsPerCyl = FSDM_SCSI_MAPPING;
  486.     geoPtr->blocksPerRotSet = 0;
  487.     geoPtr->blocksPerCylinder = blocksPerCyl;
  488.     geoPtr->tracksPerRotSet = 0;
  489.     /*
  490.      * Don't use rotational sorting anyway.
  491.      */
  492.     for (index = 0 ; index < FSDM_MAX_ROT_POSITIONS ; index++) {
  493.     geoPtr->sortedOffsets[index] = -1;
  494.     }
  495. }
  496.  
  497. /*
  498.  *----------------------------------------------------------------------
  499.  *
  500.  * SetDiskGeometry --
  501.  *
  502.  *    This computes the rotational set arrangment depending on the
  503.  *    disk geometry.  The basic rules for this are that filesystem blocks
  504.  *    are skewed on successive tracks, and that the skewing pattern
  505.  *    repeats in either 2 or 4 tracks.  This is specific to the fact that
  506.  *    filesystem blocks are 4Kbytes.  This means that one disk track
  507.  *    contains N/4 filesystem blocks and that one sector per track
  508.  *    is wasted if there are an odd number of sectors per track.
  509.  *
  510.  * Results:
  511.  *    None.
  512.  *
  513.  * Side effects:
  514.  *    Fill in the geometry struct.
  515.  *
  516.  *----------------------------------------------------------------------
  517.  */
  518. void
  519. SetDiskGeometry(labelPtr, geoPtr)
  520.     register Disk_Label *labelPtr;/* Basic geometry information */
  521.     register Fsdm_Geometry *geoPtr;    /* Fancy geometry information */
  522. {
  523.     register int index;        /* Array index */
  524.     int numBlocks;        /* The number of blocks in a rotational set */
  525.     int tracksPerSet;        /* Total number of tracks in a rotational set */
  526.     int numTracks;        /* The number of tracks in the set so far */
  527.     int extraSectors;        /* The number of leftover sectors in a track */
  528.     int offset;            /* The sector offset within a track */
  529.     int startingOffset;        /* The offset of the first block in a track */
  530.     int offsetIncrement;    /* The skew of the starting offset on each
  531.                  * successive track of the rotational set */
  532.     Boolean overlap;        /* TRUE if filesystem blocks overlap tracks */
  533.  
  534.     geoPtr->numHeads = labelPtr->numHeads;
  535.     geoPtr->sectorsPerTrack = labelPtr->numSectors;
  536.  
  537.     /*
  538.      * Figure out some basic parameters of the rotational set.  The number
  539.      * of tracks in the set is either 2 or 4.  If 2, then the blocks on
  540.      * successive tracks are skewed by 1/2 a filesystem block.  If 4,
  541.      * blocks are skewed by 1/4 block.  A 4 track rotational set is best
  542.      * becasue there are more rotational positions.  If, however, it
  543.      * causes 2 or 3 wasted tracks at the end, or if blocks naturally
  544.      * overlap by 1/2 block, then only 2 tracks per rotational set are
  545.      * used.
  546.      */
  547.     switch(geoPtr->numHeads % 4) {
  548.     case 0:
  549.     case 1: {
  550.         extraSectors = geoPtr->sectorsPerTrack % DISK_SECTORS_PER_BLOCK;
  551.         if (extraSectors < DISK_SECTORS_PER_BLOCK/4) {
  552.         /*
  553.          * Not enough extra sectors to overlap blocks onto the
  554.          * next track.  The blocks will fit evenly on a track,
  555.          * but the blocks on the following tracks will be skewed.
  556.          */
  557.         tracksPerSet = 4;
  558.         overlap = FALSE;
  559.         offsetIncrement = DISK_SECTORS_PER_BLOCK/4;
  560.         } else if (extraSectors < DISK_SECTORS_PER_BLOCK/2) {
  561.         /*
  562.          * Enough to overlap the first 1/4 block onto the next track.
  563.          */
  564.         tracksPerSet = 4;
  565.         overlap = TRUE;
  566.         offsetIncrement = DISK_SECTORS_PER_BLOCK * 3/4;
  567.         } else if (extraSectors < DISK_SECTORS_PER_BLOCK * 3/4) {
  568.         /*
  569.          * Enough to overlap 1/2 block.
  570.          */
  571.         tracksPerSet = 2;
  572.         overlap = TRUE;
  573.         offsetIncrement = DISK_SECTORS_PER_BLOCK/2;
  574.         } else {
  575.         /*
  576.          * Enough to overlap 3/4 block.
  577.          */
  578.         tracksPerSet = 4;
  579.         overlap = TRUE;
  580.         offsetIncrement = DISK_SECTORS_PER_BLOCK/4;
  581.         }
  582.         break;
  583.     }
  584.     case 2:
  585.     case 3: {
  586.         /*
  587.          * Instead of wasting 2 or 3 tracks to have a 4 track rotational
  588.          * set, the rotational set is only 2 tracks long.  Also see if
  589.          * the blocks naturally overlap by 1/2 block.
  590.          */
  591.         tracksPerSet = 2;
  592.         offsetIncrement = DISK_SECTORS_PER_BLOCK/2;
  593.         if ((geoPtr->sectorsPerTrack % DISK_SECTORS_PER_BLOCK) <
  594.               DISK_SECTORS_PER_BLOCK/2) {
  595.         overlap = FALSE;
  596.         } else {
  597.         overlap = TRUE;
  598.         }
  599.     }
  600.     }
  601.     if (!overlapBlocks) {
  602.     overlap = FALSE;
  603.     offsetIncrement = 0;
  604.     }
  605.     printf("overlap %s, offsetIncrement %d\n", (overlap ? "TRUE" : "FALSE"),
  606.               offsetIncrement);
  607.     /*
  608.      * Determine rotational position of the blocks in the rotational set.
  609.      */
  610.     extraSectors = geoPtr->sectorsPerTrack;
  611.     startingOffset = 0;
  612.     offset = startingOffset;
  613.     for (numBlocks = 0, numTracks = 0 ; ; ) {
  614.     if (extraSectors >= DISK_SECTORS_PER_BLOCK) {
  615.         /*
  616.          * Ok to fit in another filesystem block on this track.
  617.          */
  618.         geoPtr->blockOffset[numBlocks] = offset;
  619.         numBlocks++;    
  620.         offset += DISK_SECTORS_PER_BLOCK;
  621.         extraSectors -= DISK_SECTORS_PER_BLOCK;
  622.     } else {
  623.         /*
  624.          * The current block has to take up room on the next track.
  625.          */
  626.         numTracks++;
  627.         if (numTracks < tracksPerSet) {
  628.         /*
  629.          * Ok to go to the next track.
  630.          */
  631.         startingOffset += offsetIncrement;
  632.         if (overlap) {
  633.             /*
  634.              * If the current block can overlap to the next track,
  635.              * use the current offset.  Because of the overlap
  636.              * there are fewer sectors available for blocks on
  637.              * the next track.
  638.              */
  639.             geoPtr->blockOffset[numBlocks] = offset;
  640.             numBlocks++;
  641.             extraSectors = geoPtr->sectorsPerTrack - startingOffset;
  642.         }
  643.         offset = startingOffset + numTracks * geoPtr->sectorsPerTrack;
  644.         if (!overlap) {
  645.             /*
  646.              * If no overlap the whole next track is available.
  647.              */
  648.             extraSectors = geoPtr->sectorsPerTrack;
  649.         }
  650.         } else {
  651.         /*
  652.          * Done.
  653.          */
  654.         for (index = numBlocks; index < FSDM_MAX_ROT_POSITIONS; index++){
  655.             geoPtr->blockOffset[index] = -1;
  656.         }
  657.         break;
  658.         }
  659.     }
  660.     }
  661.     geoPtr->blocksPerRotSet = numBlocks;
  662.     geoPtr->tracksPerRotSet = tracksPerSet;
  663.     geoPtr->rotSetsPerCyl = geoPtr->numHeads / tracksPerSet;
  664.     geoPtr->blocksPerCylinder = numBlocks * geoPtr->rotSetsPerCyl;
  665.  
  666.     /*
  667.      * Now the rotational positions have to be sorted so that rotationally
  668.      * optimal blocks can be found.  The array sortedOffsets is set so
  669.      * that the I'th element has the index into blockOffset which contains
  670.      * the I'th rotational position, eg.
  671.      *    blockOffset    sortedOffsets
  672.      *        0 (+0)        0
  673.      *        8 (+0)        2
  674.      *        4 (+17)        1
  675.      *       12 (+17)        3
  676.      */
  677.  
  678.     offsetIncrement = DISK_SECTORS_PER_BLOCK / tracksPerSet;
  679.     for (index = 0 ; index < FSDM_MAX_ROT_POSITIONS ; index++) {
  680.     geoPtr->sortedOffsets[index] = -1;
  681.     }
  682.     for (index = 0 ; index < numBlocks ; index++) {
  683.     offset = geoPtr->blockOffset[index] % geoPtr->sectorsPerTrack;
  684.     geoPtr->sortedOffsets[offset/offsetIncrement] = index;
  685.     }
  686. }
  687.  
  688. /*
  689.  *----------------------------------------------------------------------
  690.  *
  691.  * SetDomainParts --
  692.  *
  693.  *    Set up the way the domain is divided into 4 areas:  the bitmap
  694.  *    for the file descriptors, the file descriptors, the bitmap for
  695.  *    the data blocks, and the data blocks.
  696.  *
  697.  * Results:
  698.  *    The geometry information is completed.
  699.  *
  700.  * Side effects:
  701.  *    None.
  702.  *
  703.  *----------------------------------------------------------------------
  704.  */
  705. void
  706. SetDomainParts(labelPtr, partition, headerPtr)
  707.     register Disk_Label        *labelPtr;    /* The disk label. */
  708.     int partition;
  709.     register Fsdm_DomainHeader *headerPtr;
  710. {
  711.     register Fsdm_Geometry *geoPtr;
  712.     int numFiles;        /* Number of files computed from the size */
  713.     int numBlocks;        /* Number of blocks in the partition.  This
  714.                  * is computed and then dolled out to the
  715.                  * different things stored in the partition */
  716.     int offset;            /* Block offset within partition */
  717.     int bitmapBytes;        /* Number of bytes taken up by a bitmap */
  718.     int reservedBlocks;        /* Number of blocks reserved at beginning
  719.                  * of partition */
  720.     int maxSector;
  721.     int numCylinders;
  722.  
  723.     /*
  724.      * Set aside a number of blocks at the begining of the partition for
  725.      * things like the super block, the boot program, and the domain header.
  726.      */
  727.     geoPtr = &headerPtr->geometry;
  728.     maxSector = labelPtr->labelSector;
  729.     maxSector = Max(maxSector,labelPtr->bootSector + labelPtr->numBootSectors);
  730.     maxSector = Max(maxSector,labelPtr->summarySector
  731.     + labelPtr->numSummarySectors);
  732.     maxSector = Max(maxSector,labelPtr->domainSector
  733.     + labelPtr->numDomainSectors);
  734.     numCylinders = labelPtr->partitions[partition].numCylinders;
  735.     if (scsiDisk) {
  736.     /*
  737.      * For a scsi disk just reserve whole cylinders.
  738.      */
  739.     int cylinders;
  740.     cylinders = maxSector / (geoPtr->sectorsPerTrack * geoPtr->numHeads);
  741.     if ((maxSector % (geoPtr->sectorsPerTrack * geoPtr->numHeads)) != 0) {
  742.         cylinders++;
  743.     }
  744.     reservedBlocks = cylinders * geoPtr->blocksPerCylinder;
  745.     numBlocks = geoPtr->blocksPerCylinder * numCylinders - reservedBlocks;
  746.      } else {
  747.     /*
  748.      * If we are using rotational sets then reserve whole sets.
  749.      */
  750.     int sets;
  751.     sets = maxSector / (geoPtr->tracksPerRotSet * geoPtr->sectorsPerTrack);
  752.     if ((maxSector % (geoPtr->tracksPerRotSet * geoPtr->sectorsPerTrack)) 
  753.     != 0) {
  754.         sets++;
  755.     }
  756.     reservedBlocks = sets * geoPtr->blocksPerRotSet;
  757.     numBlocks = geoPtr->blocksPerCylinder * numCylinders - reservedBlocks;
  758.     }
  759.     printf("Reserving %d blocks for domain header, etc.\n", reservedBlocks);
  760.     /*
  761.      * Determine the number of filesystem blocks available and compute a
  762.      * first guess at the number of file descriptors.  If at the end of
  763.      * the computation things don't fit nicely, then the number of files
  764.      * is changed and the computation is repeated.
  765.      */
  766.     numFiles = 0;
  767.     do {
  768.     if (numFiles == 0) {
  769.         numFiles = numBlocks * DISK_KBYTES_PER_BLOCK / kbytesToFileDesc;
  770.     }
  771.     numFiles          &= ~(FSDM_FILE_DESC_PER_BLOCK-1);
  772.     offset              = reservedBlocks;
  773.  
  774.     headerPtr->fdBitmapOffset = offset;
  775.     bitmapBytes          = (numFiles - 1) / BITS_PER_BYTE + 1;
  776.     headerPtr->fdBitmapBlocks = (bitmapBytes - 1) / FS_BLOCK_SIZE + 1;
  777.     numBlocks          -= headerPtr->fdBitmapBlocks;
  778.     offset              += headerPtr->fdBitmapBlocks;
  779.  
  780.     headerPtr->fileDescOffset = offset;
  781.     headerPtr->numFileDesc      = numFiles;
  782.     numBlocks          -= numFiles / FSDM_FILE_DESC_PER_BLOCK;
  783.     offset              += numFiles / FSDM_FILE_DESC_PER_BLOCK;
  784.     /*
  785.      * The data blocks will start on a cylinder.  Try the next
  786.      * cylinder boundary after the start of the bitmap.
  787.      */
  788.     headerPtr->bitmapOffset      = offset;
  789.     headerPtr->dataOffset      = ((offset-1) / geoPtr->blocksPerCylinder + 1)
  790.                      * geoPtr->blocksPerCylinder;
  791.     headerPtr->dataBlocks      = headerPtr->numCylinders *
  792.                       geoPtr->blocksPerCylinder -
  793.                       headerPtr->dataOffset;
  794.     bitmapBytes          = (headerPtr->dataBlocks * DISK_KBYTES_PER_BLOCK -
  795.                        1) / BITS_PER_BYTE + 1;
  796.     headerPtr->bitmapBlocks      = (bitmapBytes - 1) / FS_BLOCK_SIZE + 1;
  797.     /*
  798.      * Check the size of the bit map against space available for it
  799.      * between the end of the file descriptors and the start of the
  800.      * data blocks.
  801.      */
  802.     if (headerPtr->dataOffset - headerPtr->bitmapOffset <
  803.         headerPtr->bitmapBlocks) {
  804.         int numBlocksNeeded;
  805.         /*
  806.          * Need more blocks to hold the bitmap.  Reduce the number
  807.          * of file descriptors to get the blocks and re-iterate.
  808.          */
  809.         numBlocksNeeded = headerPtr->bitmapBlocks -
  810.         (headerPtr->dataOffset - headerPtr->bitmapOffset);
  811.         numFiles -= numBlocksNeeded * FSDM_FILE_DESC_PER_BLOCK;
  812.     } else if (headerPtr->dataOffset - headerPtr->bitmapOffset >
  813.             headerPtr->bitmapBlocks) {
  814.         int extraBlocks;
  815.         /*
  816.          * There are extra blocks between the end of the file descriptors
  817.          * and the start of the bitmap.  Increase the number of
  818.          * file descriptors and re-iterate.
  819.          */
  820.         extraBlocks = headerPtr->dataOffset - headerPtr->bitmapOffset -
  821.             headerPtr->bitmapBlocks;
  822.         numFiles += extraBlocks * FSDM_FILE_DESC_PER_BLOCK;
  823.     }
  824.     } while (headerPtr->dataOffset - headerPtr->bitmapOffset !=
  825.         headerPtr->bitmapBlocks);
  826.     headerPtr->dataCylinders    = headerPtr->dataBlocks /
  827.                   geoPtr->blocksPerCylinder ;
  828. }
  829. /*
  830.  *----------------------------------------------------------------------
  831.  *
  832.  * SetSummaryInfo --
  833.  *
  834.  *    This routine is out of date and writes bogus info to the disk.
  835.  *    Fscheck should fix the data anyway.
  836.  *
  837.  * Results:
  838.  *    A return code.
  839.  *
  840.  * Side effects:
  841.  *    Fill in the summary info.
  842.  *
  843.  *----------------------------------------------------------------------
  844.  */
  845. void
  846. SetSummaryInfo(labelPtr, headerPtr, summaryPtr)
  847.     Disk_Label *labelPtr;    /* Information from the super block */
  848.     Fsdm_DomainHeader *headerPtr;    /* Domain header to summarize */
  849.     Fsdm_SummaryInfo *summaryPtr;    /* Reference to summary info to fill in */
  850. {
  851.  
  852.     bzero((Address)summaryPtr, DEV_BYTES_PER_SECTOR);
  853.  
  854.     strcpy(summaryPtr->domainPrefix, "(new domain)");
  855.     /*
  856.      * 9 blocks are already allocated, one for the root directory,
  857.      * and 8 more for lost+found.
  858.      */
  859.     summaryPtr->numFreeKbytes = headerPtr->dataBlocks * (FS_BLOCK_SIZE / 1024)
  860.                 - 9;
  861.     /*
  862.      * 4 file descriptors are already used, 0 and 1 are reserved,
  863.      * 2 is for the root, and 3 is for lost+found.
  864.      */
  865.     summaryPtr->numFreeFileDesc = headerPtr->numFileDesc - 5;
  866.     if (makeFile) {
  867.     summaryPtr->numFreeFileDesc--;
  868.     }
  869.     /*
  870.      * The summary state field is unused.
  871.      */
  872.     summaryPtr->state = 0;
  873.     /*
  874.      * The domain number under which this disk partition is mounted is
  875.      * recorded on disk so servers re-attach disks under the same "name".
  876.      * We set it to the special value so it gets a new number assigned
  877.      * when it is first attached.
  878.      */
  879.     summaryPtr->domainNumber = -1;
  880.     /*
  881.      * The flags field is used to record whether or not the disk has been
  882.      * safely "sync"ed to disk upon shutdown.
  883.      */
  884.     summaryPtr->flags = 0;
  885.     summaryPtr->fixCount = 0;
  886. }
  887.  
  888. /*
  889.  *----------------------------------------------------------------------
  890.  *
  891.  * WriteFileDesc --
  892.  *
  893.  *    Write out the file descriptor array to disk.
  894.  *
  895.  * Results:
  896.  *    None.
  897.  *
  898.  * Side effects:
  899.  *    None.
  900.  *
  901.  *----------------------------------------------------------------------
  902.  */
  903. ReturnStatus
  904. WriteFileDesc(headerPtr, partFID)
  905.     register Fsdm_DomainHeader *headerPtr;
  906.     int partFID;    /* File handle for partition to format */
  907. {
  908.     ReturnStatus status;
  909.     char *bitmap;
  910.     char *block;
  911.     register Fsdm_FileDescriptor *fileDescPtr;
  912.     register int index;
  913.  
  914.     bitmap = MakeFileDescBitmap(headerPtr);
  915.     if (!printOnly) {
  916.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->fdBitmapOffset,
  917.                 headerPtr->fdBitmapBlocks, (Address)bitmap);
  918.     if (status != SUCCESS) {
  919.         return(status);
  920.     }
  921.     }
  922.     /*
  923.      * Make the first block of file descriptors.  This contains some
  924.      * canned file descriptors for the root, bad block file, and the
  925.      * lost and found directory.  For (early system) testing an empty file
  926.      * can also be created.
  927.      */
  928.     block = (char *)malloc(FS_BLOCK_SIZE);
  929.     bzero(block, FS_BLOCK_SIZE);
  930.     for (index = 0;
  931.          index < FSDM_FILE_DESC_PER_BLOCK;
  932.      index++ ) {
  933.     fileDescPtr = (Fsdm_FileDescriptor *)((int)block +
  934.                        index * FSDM_MAX_FILE_DESC_SIZE);
  935.     fileDescPtr->magic = FSDM_FD_MAGIC;
  936.     if (index < FSDM_BAD_BLOCK_FILE_NUMBER) {
  937.         fileDescPtr->flags = FSDM_FD_RESERVED;
  938.     } else if (index == FSDM_BAD_BLOCK_FILE_NUMBER) {
  939.         SetBadBlockFileDescriptor(fileDescPtr);
  940.     } else if (index == FSDM_ROOT_FILE_NUMBER) {
  941.         SetRootFileDescriptor(fileDescPtr);
  942.     } else if (index == FSDM_LOST_FOUND_FILE_NUMBER) {
  943.         SetLostFoundFileDescriptor(fileDescPtr);
  944.     } else if ((index == 4) && makeFile) {
  945.         SetEmptyFileDescriptor(fileDescPtr);
  946.     } else if ((index == 5)) {
  947.         SetEmptyFileDescriptor(fileDescPtr);
  948.     } else if ((index == 6)) {
  949.         SetTooBigFD(fileDescPtr);
  950.     } else if ((index == 7)) {
  951.         SetTooSmallFD(fileDescPtr);
  952.     } else if ((index == 8)) {
  953.         SetHoleFileFD(headerPtr, partFID, fileDescPtr);
  954.     } else if ((index == 9)) {
  955.         SetHoleDirFD(headerPtr, partFID, fileDescPtr);
  956.     } else if ((index == 10)) {
  957.         SetBadEntryFileFD(headerPtr, partFID, fileDescPtr);
  958.     } else if ((index == 11)) {
  959.         SetFragFileFD(fileDescPtr);    
  960.     } else if ((index == 12)) {
  961.         SetCopyFragFileFD(fileDescPtr);    
  962.     } else if ((index == 13)) {
  963.         SetCopyBlockFileFD(fileDescPtr);    
  964.     } else if ((index == 14)) {
  965.         SetCopyIndBlockFileFD(headerPtr, partFID, fileDescPtr);    
  966.     } else if ((index == 15)) {
  967.         SetCopyBogusIndBlockFileFD(headerPtr, partFID, fileDescPtr);    
  968.     } else if ((index == 16)) {
  969.         fileDescPtr->magic = ~FSDM_FD_MAGIC;
  970.     } else if ((index == 17)) {
  971.         SetDirFD(fileDescPtr);
  972.     } else if ((index == 18)) {
  973.         SetOutputFD(fileDescPtr);
  974.     } else if ((index == 21)) {
  975.         SetBadDotDotFD(fileDescPtr);
  976.     } else {
  977.         fileDescPtr->flags = FSDM_FD_FREE;
  978.     }
  979.     }
  980.     if (!printOnly) {
  981.     /*
  982.      * Write out the first, specially hand crafted, block of file
  983.      * descriptors.
  984.      */
  985.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->fileDescOffset,
  986.                     1, (Address)block);
  987.     if (status != SUCCESS) {
  988.         return(status);
  989.     }
  990.     /*
  991.      * Redo the block for the remaining file descriptors
  992.      */
  993.     bzero(block, FS_BLOCK_SIZE);
  994.     for (index = 0;
  995.          index < FSDM_FILE_DESC_PER_BLOCK;
  996.          index++ ) {
  997.         fileDescPtr = (Fsdm_FileDescriptor *)((int)block + index *
  998.                            FSDM_MAX_FILE_DESC_SIZE);
  999.         fileDescPtr->magic = FSDM_FD_MAGIC;
  1000.         fileDescPtr->flags = FSDM_FD_FREE;
  1001.     }
  1002.     /*
  1003.      * Write out the remaining file descriptors.
  1004.      */
  1005.     for (index = FSDM_FILE_DESC_PER_BLOCK;
  1006.          index < headerPtr->numFileDesc;
  1007.          index += FSDM_FILE_DESC_PER_BLOCK) {
  1008.         status = Disk_BlockWrite(partFID, headerPtr,
  1009.              headerPtr->fileDescOffset + (index/FSDM_FILE_DESC_PER_BLOCK),
  1010.              1, (Address)block);
  1011.         if (status != SUCCESS) {
  1012.         return(status);
  1013.         }
  1014.     }
  1015.     } else {
  1016.     status = SUCCESS;
  1017.     }
  1018.     return(status);
  1019. }
  1020.  
  1021. /*
  1022.  * This macro makes setting bits in the fd and data block bitmap easier.
  1023.  */
  1024.  
  1025. #define SET(num)  {   bitmap[(num) >> 3] |=(1 << (7 - ((num) & 0x7))); }
  1026.  
  1027.  
  1028. /*
  1029.  *----------------------------------------------------------------------
  1030.  *
  1031.  * 
  1032.  * MakeFileDescBitmap --
  1033.  *
  1034.  *    Compute out the bitmap for file descriptor array to disk.
  1035.  *
  1036.  * Results:
  1037.  *    None.
  1038.  *
  1039.  * Side effects:
  1040.  *    None.
  1041.  *
  1042.  *----------------------------------------------------------------------
  1043.  */
  1044. char *
  1045. MakeFileDescBitmap(headerPtr)
  1046.     register Fsdm_DomainHeader *headerPtr;
  1047. {
  1048.     register char *bitmap;
  1049.     register int index;
  1050.  
  1051.     /*
  1052.      * Allocate and initialize the bitmap to all 0"s to mean all free.
  1053.      */
  1054.     bitmap = (char *)malloc((unsigned) headerPtr->fdBitmapBlocks *
  1055.                  FS_BLOCK_SIZE);
  1056.     bzero((Address)bitmap, headerPtr->fdBitmapBlocks * FS_BLOCK_SIZE);
  1057.  
  1058.     SET(0);
  1059.     SET(1);
  1060.     if (!noRoot) {
  1061.     SET(2);
  1062.     }
  1063.     SET(3);
  1064.     SET(4);
  1065.     SET(6);
  1066.     SET(7);
  1067.     SET(8);
  1068.     SET(9);
  1069.     SET(10);
  1070.     SET(11);
  1071.     SET(12);
  1072.     SET(13);
  1073.     SET(14);
  1074.     SET(15);
  1075.     /*
  1076.      * 16 is allocated but not marked in the bitmap.
  1077.      */
  1078.     SET(17);
  1079.     SET(18);
  1080.     /*
  1081.      * 20 is marked in the bitmap but not used.
  1082.      */
  1083.     SET(20);
  1084.  
  1085.     SET(21);
  1086.     /*
  1087.      * Don't set 22 -- it is used by directory 21. 
  1088.      */
  1089.     /*
  1090.      * Set the bits in the map at the end that don't correspond to
  1091.      * any existing file descriptors.
  1092.      */
  1093.     index = headerPtr->numFileDesc / BITS_PER_BYTE;
  1094.     if (headerPtr->numFileDesc % BITS_PER_BYTE) {
  1095.     register int bitIndex;
  1096.     /*
  1097.      * Take care the last byte that only has part of its bits set.
  1098.      */
  1099.     for (bitIndex = headerPtr->numFileDesc % BITS_PER_BYTE;
  1100.          bitIndex < BITS_PER_BYTE;
  1101.          bitIndex++) {
  1102.         bitmap[index] |= 1 << ((BITS_PER_BYTE - 1) - bitIndex);
  1103.     }
  1104.     index++;
  1105.     }
  1106.     for ( ; index < headerPtr->fdBitmapBlocks * FS_BLOCK_SIZE; index++) {
  1107.     bitmap[index] = 0xff;
  1108.     }
  1109.  
  1110.     if (printOnly) {
  1111.     Disk_PrintFileDescBitmap(headerPtr, bitmap);
  1112.     }
  1113.     return(bitmap);
  1114. }
  1115.  
  1116. /* 
  1117.  * This macro makes setting an entire block (4 fragments) easier. The block
  1118.  * to set must be on a block boundary.
  1119.  */
  1120.  
  1121. #define SET4K(num)  {   bitmap[(num) >> 3] |=(0xf << (4 - ((num) & 0x7))); }
  1122.  
  1123.  
  1124. /*
  1125.  *----------------------------------------------------------------------
  1126.  *
  1127.  * WriteBitmap --
  1128.  *
  1129.  *    Write out the bitmap for the data blocks.  This knows that the
  1130.  *    first 1K fragment is allocated to the root directory and 8K is
  1131.  *    allocated to lost and found, plus lots of other blocks are allocated
  1132.  *    to the rest of the files.
  1133.  *
  1134.  * Results:
  1135.  *    A return code from the writes.
  1136.  *
  1137.  * Side effects:
  1138.  *    Write the bitmap.
  1139.  *
  1140.  *----------------------------------------------------------------------
  1141.  */
  1142. ReturnStatus
  1143. WriteBitmap(headerPtr, partFID)
  1144.     register Fsdm_DomainHeader *headerPtr;
  1145.     int partFID;
  1146. {
  1147.     ReturnStatus status;
  1148.     char *bitmap;
  1149.     int kbytesPerCyl;
  1150.     int bitmapBytesPerCyl;
  1151.     int index;
  1152.  
  1153.     bitmap = (char *)malloc((unsigned) headerPtr->bitmapBlocks * FS_BLOCK_SIZE);
  1154.     bzero(bitmap, headerPtr->bitmapBlocks * FS_BLOCK_SIZE);
  1155.     /*
  1156.      * Set the bit corresponding to the kbyte used for the root directory
  1157.      * and the next 8K reserved for lost and found.
  1158.      *   ________
  1159.      *    |0______7|    Bits are numbered like this in a byte.
  1160.      *
  1161.      * See fstrash.man for info on how these blocks are used
  1162.      */
  1163.     if (!noRoot) {
  1164.     SET(0);
  1165.     }
  1166.     SET(1);
  1167.     SET4K(4);
  1168.     SET(8);
  1169.     SET(9);
  1170.  
  1171.     SET(11);
  1172.     SET4K(12);
  1173.     SET(16);
  1174.     SET(17);
  1175.  
  1176.     SET4K(32);
  1177.     SET4K(36);
  1178.  
  1179.     SET4K(44);
  1180.     SET4K(48);
  1181.     SET4K(52);
  1182.     SET4K(56);
  1183.  
  1184.     SET(61);
  1185.     SET(62);
  1186.  
  1187.     SET(64);
  1188.  
  1189.     SET4K(68);
  1190.     SET4K(72);
  1191.  
  1192.     SET(76);
  1193.  
  1194.     /*
  1195.      * The bitmap is organized by cylinder.  There are whole number of
  1196.      * bytes in the bitmap for each cylinder.  Each bit in the bitmap
  1197.      * corresponds to 1 kbyte on the disk.
  1198.      */
  1199.     kbytesPerCyl = headerPtr->geometry.blocksPerCylinder * DISK_KBYTES_PER_BLOCK;
  1200.     bitmapBytesPerCyl = (kbytesPerCyl - 1) / BITS_PER_BYTE + 1;
  1201.     if ((kbytesPerCyl % BITS_PER_BYTE) != 0) {
  1202.     /*
  1203.      * There are bits in the last byte of the bitmap for each cylinder
  1204.      * that don't have kbytes behind them.  Set those bits here so
  1205.      * the blocks don't get allocated.
  1206.      */
  1207.     register int extraBits;
  1208.     register int mask;
  1209.  
  1210.     extraBits = kbytesPerCyl % BITS_PER_BYTE;
  1211.     /*
  1212.      * Set up a mask that has the right part filled with 1"s.
  1213.      */
  1214.     mask = 0x0;
  1215.     for ( ; extraBits < BITS_PER_BYTE ; extraBits++) {
  1216.         mask |= 1 << ((BITS_PER_BYTE - 1) - extraBits);
  1217.     }
  1218.     for (index = 0;
  1219.          index < headerPtr->dataBlocks * DISK_KBYTES_PER_BLOCK / BITS_PER_BYTE;
  1220.          index += bitmapBytesPerCyl) {
  1221.         bitmap[index + bitmapBytesPerCyl - 1] |= mask;
  1222.     }
  1223.     }
  1224.     /*
  1225.      * Set the bits in the bitmap that correspond to non-existent cylinders;
  1226.      * the bitmap is allocated a whole number of blocks on the disk
  1227.      * so there are bytes at its end that don't have blocks behind them.
  1228.      */
  1229.  
  1230.     for (index = headerPtr->dataCylinders * bitmapBytesPerCyl;
  1231.      index < headerPtr->bitmapBlocks * FS_BLOCK_SIZE;
  1232.      index++) {
  1233.     bitmap[index] = 0xff;
  1234.     }
  1235.     if (printOnly) {
  1236.     Disk_PrintDataBlockBitmap(headerPtr, bitmap);
  1237.     status = SUCCESS;
  1238.     } else {
  1239.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->bitmapOffset,
  1240.                 headerPtr->bitmapBlocks, (Address)bitmap);
  1241.     }
  1242.     return(status);
  1243. }
  1244.  
  1245. /*
  1246.  *----------------------------------------------------------------------
  1247.  *
  1248.  * WriteRootDirectory --
  1249.  *
  1250.  *    Write the data blocks of the root directory.
  1251.  *
  1252.  * Results:
  1253.  *    A return code from the writes.
  1254.  *
  1255.  * Side effects:
  1256.  *    Write the root directory"s data block.
  1257.  *
  1258.  *----------------------------------------------------------------------
  1259.  */
  1260. ReturnStatus
  1261. WriteRootDirectory(headerPtr, partFID)
  1262.     register Fsdm_DomainHeader *headerPtr;
  1263.     int partFID;
  1264. {
  1265.     ReturnStatus status;
  1266.     char block[FS_BLOCK_SIZE];
  1267.     Fslcl_DirEntry *dirEntryPtr;
  1268.     int offset;
  1269.     int i;
  1270.  
  1271.     bzero((Address) block, FS_BLOCK_SIZE);
  1272.  
  1273.     if (!noRoot) {
  1274.  
  1275.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1276.     
  1277.     offset = FillDirEntry(dirEntryPtr,".",FSDM_ROOT_FILE_NUMBER);
  1278.  
  1279.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1280.     offset += FillDirEntry(dirEntryPtr,"..",FSDM_ROOT_FILE_NUMBER);
  1281.     
  1282.     /*
  1283.      * Add lost and found.
  1284.      */
  1285.     
  1286.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1287.     offset += FillDirEntry(dirEntryPtr,"lost+found",
  1288.                    FSDM_LOST_FOUND_FILE_NUMBER);
  1289.     
  1290.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1291.     offset += FillDirEntry(dirEntryPtr,"testFile",4);
  1292.     
  1293.     /*
  1294.      * file 5 is an unreferenced file
  1295.      */
  1296.     
  1297.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1298.     offset += FillDirEntry(dirEntryPtr,"tooBig",6);
  1299.     
  1300.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1301.     offset += FillDirEntry(dirEntryPtr,"tooSmall",7);
  1302.     
  1303.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1304.     offset += FillDirEntry(dirEntryPtr,"holeFile",8);
  1305.     
  1306.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1307.     offset += FillDirEntry(dirEntryPtr,"holeDir",9);
  1308.     
  1309.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1310.     offset += FillDirEntry(dirEntryPtr,"badIndexFile",10);
  1311.     
  1312.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1313.     offset += FillDirEntry(dirEntryPtr,"illegalFrag",11);
  1314.     
  1315.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1316.     offset += FillDirEntry(dirEntryPtr,"copyBadFrag",12);
  1317.     
  1318.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1319.     offset += FillDirEntry(dirEntryPtr,"copyBlock",13);
  1320.     
  1321.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1322.     offset += FillDirEntry(dirEntryPtr,"copyIndBlock",14);
  1323.     
  1324.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1325.     offset += FillDirEntry(dirEntryPtr,"copyBogusInd",15);
  1326.     /*
  1327.      * 16 and 17 are unreferenced.
  1328.      */
  1329.     
  1330.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1331.     offset += FillDirEntry(dirEntryPtr,"output",18);
  1332.  
  1333.     dirEntryPtr = (Fslcl_DirEntry *) ((int)block + offset);
  1334.     offset += FillDirEntry(dirEntryPtr,"badDotDot",21);
  1335.  
  1336.     dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - offset +
  1337.                     dirEntryPtr->recordLength;
  1338.  
  1339.     for (dirEntryPtr = (Fslcl_DirEntry *)&block[FSLCL_DIR_BLOCK_SIZE], i = 1; 
  1340.      i < FS_BLOCK_SIZE / FSLCL_DIR_BLOCK_SIZE;
  1341.      i++,dirEntryPtr=(Fslcl_DirEntry *)((int)dirEntryPtr + FSLCL_DIR_BLOCK_SIZE)) {
  1342.      dirEntryPtr->fileNumber = 0;
  1343.      dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  1344.      dirEntryPtr->nameLength = 0;
  1345.     }
  1346.  
  1347.     }
  1348.     if (printOnly) {
  1349.     printf("Root Directory\n");
  1350.     offset = 0;
  1351.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1352.     while (offset + dirEntryPtr->recordLength != FSLCL_DIR_BLOCK_SIZE) {
  1353.         Disk_PrintDirEntry(dirEntryPtr);
  1354.         offset += dirEntryPtr->recordLength;
  1355.         dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1356.     }
  1357.     status = SUCCESS;
  1358.     } else {
  1359.     /*
  1360.      * This write trounces the data beyond the stuff allocated to
  1361.      * the root directory.  Currently this is ok and is done because
  1362.      * BlockWrite writes whole numbers of filesystem blocks.
  1363.      */
  1364.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->dataOffset, 1,
  1365.                        block);
  1366.     }
  1367.     return(status);
  1368. }
  1369.  
  1370. /*
  1371.  *----------------------------------------------------------------------
  1372.  *
  1373.  * WriteLostFoundDirectory --
  1374.  *
  1375.  *    Write the data blocks of the lost and found directory.
  1376.  *
  1377.  * Results:
  1378.  *    A return code from the writes.
  1379.  *
  1380.  * Side effects:
  1381.  *    Write the root directory"s data block.
  1382.  *
  1383.  *----------------------------------------------------------------------
  1384.  */
  1385. ReturnStatus
  1386. WriteLostFoundDirectory(headerPtr, partFID)
  1387.     register Fsdm_DomainHeader *headerPtr;
  1388.     int partFID;
  1389. {
  1390.     ReturnStatus status;
  1391.     char *block;
  1392.     Fslcl_DirEntry *dirEntryPtr;
  1393.     char *fileName;
  1394.     int length;
  1395.     int offset;
  1396.     int    i;
  1397.  
  1398.     block = (char *)malloc(FSDM_NUM_LOST_FOUND_BLOCKS * FS_BLOCK_SIZE);
  1399.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1400.  
  1401.     fileName = ".";
  1402.     length = strlen(fileName);
  1403.     dirEntryPtr->fileNumber = FSDM_LOST_FOUND_FILE_NUMBER;
  1404.     dirEntryPtr->recordLength = Fslcl_DirRecLength(length);
  1405.     dirEntryPtr->nameLength = length;
  1406.     strcpy(dirEntryPtr->fileName, fileName);
  1407.     offset = dirEntryPtr->recordLength;
  1408.  
  1409.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1410.     fileName = "..";
  1411.     length = strlen(fileName);
  1412.     dirEntryPtr->fileNumber = FSDM_ROOT_FILE_NUMBER;
  1413.     dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - offset;
  1414.     dirEntryPtr->nameLength = length;
  1415.     strcpy(dirEntryPtr->fileName, fileName);
  1416.  
  1417.     /*
  1418.      * Fill out the rest of the directory with empty blocks.
  1419.      */
  1420.  
  1421.     for (dirEntryPtr = (Fslcl_DirEntry *)&block[FSLCL_DIR_BLOCK_SIZE], i = 1; 
  1422.      i < FSDM_NUM_LOST_FOUND_BLOCKS * FS_BLOCK_SIZE / FSLCL_DIR_BLOCK_SIZE;
  1423.      i++,dirEntryPtr=(Fslcl_DirEntry *)((int)dirEntryPtr + FSLCL_DIR_BLOCK_SIZE)) {
  1424.      dirEntryPtr->fileNumber = 0;
  1425.      dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  1426.      dirEntryPtr->nameLength = 0;
  1427.     }
  1428.     if (printOnly) {
  1429.     printf("Lost+found Directory\n");
  1430.     offset = 0;
  1431.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1432.     Disk_PrintDirEntry(dirEntryPtr);
  1433.     offset += dirEntryPtr->recordLength;
  1434.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1435.     Disk_PrintDirEntry(dirEntryPtr);
  1436.     status = SUCCESS;
  1437.     } else {
  1438.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->dataOffset + 1,
  1439.                 FSDM_NUM_LOST_FOUND_BLOCKS, block);
  1440.     }
  1441.     return(status);
  1442. }
  1443.  
  1444. /*
  1445.  *----------------------------------------------------------------------
  1446.  *
  1447.  * WriteEmptyDirectory --
  1448.  *
  1449.  *    Write the data blocks of the empty directory (file 17).
  1450.  *
  1451.  * Results:
  1452.  *    A return code from the writes.
  1453.  *
  1454.  * Side effects:
  1455.  *    None.
  1456.  *
  1457.  *----------------------------------------------------------------------
  1458.  */
  1459. ReturnStatus
  1460. WriteEmptyDirectory(headerPtr, partFID, selfFdNum, parentFdNum, blockNum)
  1461.     register Fsdm_DomainHeader *headerPtr;
  1462.     int partFID;
  1463.     int selfFdNum;
  1464.     int parentFdNum;
  1465.     int blockNum;
  1466. {
  1467.     ReturnStatus status;
  1468.     char *block;
  1469.     Fslcl_DirEntry *dirEntryPtr;
  1470.     char *fileName;
  1471.     int length;
  1472.     int offset;
  1473.     int    i;
  1474.  
  1475.     block = (char *)malloc(FS_BLOCK_SIZE);
  1476.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1477.  
  1478.     fileName = ".";
  1479.     length = strlen(fileName);
  1480.     dirEntryPtr->fileNumber = selfFdNum;
  1481.     dirEntryPtr->recordLength = Fslcl_DirRecLength(length);
  1482.     dirEntryPtr->nameLength = length;
  1483.     strcpy(dirEntryPtr->fileName, fileName);
  1484.     offset = dirEntryPtr->recordLength;
  1485.  
  1486.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1487.     fileName = "..";
  1488.     length = strlen(fileName);
  1489.     dirEntryPtr->fileNumber = parentFdNum;
  1490.     dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - offset;
  1491.     dirEntryPtr->nameLength = length;
  1492.     strcpy(dirEntryPtr->fileName, fileName);
  1493.  
  1494.     /*
  1495.      * Fill out the rest of the directory with empty blocks.
  1496.      */
  1497.  
  1498.     for (dirEntryPtr = (Fslcl_DirEntry *)&block[FSLCL_DIR_BLOCK_SIZE], i = 1; 
  1499.      i < FS_BLOCK_SIZE / FSLCL_DIR_BLOCK_SIZE;
  1500.      i++,dirEntryPtr=(Fslcl_DirEntry *)((int)dirEntryPtr + FSLCL_DIR_BLOCK_SIZE)) {
  1501.      dirEntryPtr->fileNumber = 0;
  1502.      dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  1503.      dirEntryPtr->nameLength = 0;
  1504.     }
  1505.     if (printOnly) {
  1506.     printf("empty Directory\n");
  1507.     offset = 0;
  1508.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1509.     Disk_PrintDirEntry(dirEntryPtr);
  1510.     offset += dirEntryPtr->recordLength;
  1511.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1512.     Disk_PrintDirEntry(dirEntryPtr);
  1513.     status = SUCCESS;
  1514.     } else {
  1515.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->dataOffset + 
  1516.                 (blockNum / FS_FRAGMENTS_PER_BLOCK),
  1517.                 1, block);
  1518.     }
  1519.     return(status);
  1520. }
  1521.  
  1522. /*
  1523.  *----------------------------------------------------------------------
  1524.  *
  1525.  * WriteBadDotDotDirectory --
  1526.  *
  1527.  *    Write a directory whose ".." points to an unallocated file.
  1528.  *
  1529.  * Results:
  1530.  *    A return code from the writes.
  1531.  *
  1532.  * Side effects:
  1533.  *    None.
  1534.  *
  1535.  *----------------------------------------------------------------------
  1536.  */
  1537. ReturnStatus
  1538. WriteBadDotDotDirectory(headerPtr, partFID, selfFdNum, parentFdNum, blockNum)
  1539.     register Fsdm_DomainHeader *headerPtr;
  1540.     int partFID;
  1541.     int selfFdNum;
  1542.     int parentFdNum;
  1543.     int blockNum;
  1544. {
  1545.     ReturnStatus status;
  1546.     char *block;
  1547.     Fslcl_DirEntry *dirEntryPtr;
  1548.     char *fileName;
  1549.     int length;
  1550.     int offset;
  1551.     int    i;
  1552.  
  1553.     block = (char *)malloc(FS_BLOCK_SIZE);
  1554.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1555.  
  1556.     fileName = ".";
  1557.     length = strlen(fileName);
  1558.     dirEntryPtr->fileNumber = selfFdNum;
  1559.     dirEntryPtr->recordLength = Fslcl_DirRecLength(length);
  1560.     dirEntryPtr->nameLength = length;
  1561.     strcpy(dirEntryPtr->fileName, fileName);
  1562.     offset = dirEntryPtr->recordLength;
  1563.  
  1564.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1565.     fileName = "..";
  1566.     length = strlen(fileName);
  1567.     dirEntryPtr->fileNumber = selfFdNum + 1;
  1568.     dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - offset;
  1569.     dirEntryPtr->nameLength = length;
  1570.     strcpy(dirEntryPtr->fileName, fileName);
  1571.  
  1572.     /*
  1573.      * Fill out the rest of the directory with empty blocks.
  1574.      */
  1575.  
  1576.     for (dirEntryPtr = (Fslcl_DirEntry *)&block[FSLCL_DIR_BLOCK_SIZE], i = 1; 
  1577.      i < FS_BLOCK_SIZE / FSLCL_DIR_BLOCK_SIZE;
  1578.      i++,dirEntryPtr=(Fslcl_DirEntry *)((int)dirEntryPtr + FSLCL_DIR_BLOCK_SIZE)) {
  1579.      dirEntryPtr->fileNumber = 0;
  1580.      dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  1581.      dirEntryPtr->nameLength = 0;
  1582.     }
  1583.     if (printOnly) {
  1584.     printf("empty Directory\n");
  1585.     offset = 0;
  1586.     dirEntryPtr = (Fslcl_DirEntry *)block;
  1587.     Disk_PrintDirEntry(dirEntryPtr);
  1588.     offset += dirEntryPtr->recordLength;
  1589.     dirEntryPtr = (Fslcl_DirEntry *)((int)block + offset);
  1590.     Disk_PrintDirEntry(dirEntryPtr);
  1591.     status = SUCCESS;
  1592.     } else {
  1593.     status = Disk_BlockWrite(partFID, headerPtr, headerPtr->dataOffset + 
  1594.                 (blockNum / FS_FRAGMENTS_PER_BLOCK),
  1595.                 1, block);
  1596.     }
  1597.     return(status);
  1598. }
  1599.  
  1600. /*
  1601.  *----------------------------------------------------------------------
  1602.  *
  1603.  *  FillDirEntry--
  1604.  *
  1605.  *    Fills in the directory entry.
  1606.  *
  1607.  * Results:
  1608.  *    None
  1609.  *
  1610.  * Side effects:
  1611.  *    None
  1612.  *
  1613.  *----------------------------------------------------------------------
  1614.  */
  1615. int
  1616. FillDirEntry(dirEntryPtr, fileName, fileNum)
  1617.     Fslcl_DirEntry *dirEntryPtr;
  1618.     char *fileName;
  1619.     int fileNum;
  1620. {
  1621.     int length;
  1622.  
  1623.     length = strlen(fileName);
  1624.     dirEntryPtr->fileNumber = fileNum;
  1625.     dirEntryPtr->recordLength = Fslcl_DirRecLength(length);
  1626.     dirEntryPtr->nameLength = length;
  1627.     strcpy(dirEntryPtr->fileName, fileName);
  1628.     return dirEntryPtr->recordLength;
  1629. }
  1630.